package org.grayrabbit.cms.publish.generate;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.grayrabbit.cms.entity.Admin;
import org.grayrabbit.cms.entity.PublishLog;
import org.grayrabbit.cms.entity.PublishTask;
import org.grayrabbit.cms.publish.api.Generatable;
import org.grayrabbit.cms.publish.generate.factory.AbstractFactory;
import org.grayrabbit.cms.util.FilePathSptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * @author sys53
 * @version 1.0
 * @created 2011-6-15 10:43:12
 */
public abstract class  AbstractGenerater implements Generater {
	private  static Logger log = LoggerFactory.getLogger(AbstractGenerater.class);
	protected Configuration configuration;
	protected Map<String, Object> rootMap = new HashMap<String, Object>();
	private String encode = "UTF-8";
	protected String path;
	protected Generatable generatable;
	protected Admin admin;
	protected AbstractGenerater(){
	}
	protected AbstractGenerater(Configuration configuration,String encode,String path,Generatable generatable,Admin admin){
		this.configuration = configuration;
		this.encode = encode;
		this.path = path;
		this.generatable = generatable;
		this.admin = admin;
	}
	protected AbstractGenerater(Configuration configuration,String path,Generatable generatable,Admin admin){
		this.configuration = configuration;
		this.path = path;
		this.generatable = generatable;
		this.admin = admin;
	}
	private void assermCommoMap(){
		rootMap.put("RESOURCE_URL", FilePathSptUtil.STATIC_RESOURCES_URL);
		rootMap.put("UPLOAD_URL",FilePathSptUtil.UPLOAD_URL);
		rootMap.put("CMS_URL",FilePathSptUtil.CMS_VISIT_CONTEXT_PATH);
		rootMap.put("COUNCIL_IMG_URL",FilePathSptUtil.COUNCIL_IMG_VISIT_URL);		
	}
	public void genFile(PublishTask publishTask) {
		OutputStreamWriter writer = null;
		//开始某页页面
		try{
		log.debug("genFile:"+this.toString());
		this.initRootMap();
		assermCommoMap();
		Template template = configuration.getTemplate(path);
		File file = getTargetFile();
		makeParentDir(file);
		FileOutputStream outputStream = new FileOutputStream(file);
		BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
		writer = new OutputStreamWriter(bufferedStream, encode);
		//结束某页面的记录,同时更新任务完成..
		template.process(rootMap, writer);
		writer.flush();
		logInfo(publishTask,true,null);//记入
		} catch (Exception e) {
			log.debug("generate occurde error",e);
			logInfo(publishTask,false,e);
		}
		finally{
			//log.debug("finally process");
			if(writer!=null)
				try {
					writer.close();
				} catch (IOException e) {
				}
		}
	}
	
	public ByteArrayOutputStream getStream() throws Exception {
		this.initRootMap();
		assermCommoMap();
		Template template = configuration.getTemplate(path);
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		OutputStreamWriter writer = new OutputStreamWriter(outputStream, encode);
		try {
			template.process(rootMap, writer);
			writer.flush();
		} catch (Throwable e) {
			throw new Exception(e);
		}
		return outputStream;
	}
	
	private void makeParentDir(File file) {
		File parent = file.getParentFile();
		if(!parent.exists()) {
			parent.mkdirs();
		}
	}
	protected boolean needAddFinished(){
		return true;
	}
	protected void calcTaskInfo(PublishTask publishTask,boolean success){
		if(needAddFinished()){
			synchronized (AbstractFactory.LOCK) {
				int finished = AbstractFactory.percent.get(publishTask.getTaskName()+AbstractFactory.FINISHED).intValue();
				int total = AbstractFactory.percent.get(publishTask.getTaskName()+AbstractFactory.TOTAL).intValue();
				int failured = AbstractFactory.percent.get(publishTask.getTaskName()+AbstractFactory.FAIL).intValue();
				finished++;
				log.debug("Current finshed task num is {}",finished);
				log.debug("calcTaskInfo:"+this.toString());
				AbstractFactory.percent.put(publishTask.getTaskName()+AbstractFactory.FINISHED,Integer.valueOf(finished));
				if(success){
					publishTask.setCreateCount(Integer.valueOf(finished-failured));
				}else{
					failured++;
					log.debug("Current failured task num is {}",failured);
					AbstractFactory.percent.put(publishTask.getTaskName()+AbstractFactory.FAIL,Integer.valueOf(failured));
					publishTask.setErrorCount(Integer.valueOf(failured));
				}
				if(total==finished){
					Date now = new Date();
					publishTask.setTaskStatus(PublishTask.STATUS_FINISHED);//任务执行完成
					publishTask.setTaskEndTime(now);
					PublishLog aPublishLog = new PublishLog();
					aPublishLog.setIsError(Boolean.FALSE);
					aPublishLog.setPublishStatus(PublishTask.STATUS_FINISHED);
					aPublishLog.setPublishTime(now);
					aPublishLog.setPublishTask(publishTask);
					aPublishLog.setPublishType("");//无发布类型
					aPublishLog.setPublishInfo("本次发布任务结束");
					log.debug("===========本次发布任务结束=============");
					generatable.savePublishLog(aPublishLog);
					AbstractFactory.PUBLISHSTATUS.remove(publishTask.getTaskName());//任务结束，删除执行的任务状态
					AbstractFactory.PUBLISHMAP.remove(publishTask.getTaskName());//任务结束，删除任务执行的对应的任务ID
					AbstractFactory.percent.put(publishTask.getTaskName()+AbstractFactory.TIME, Integer.valueOf((int)(new Date()).getTime()));
	//				AbstractFactory.percent.remove(publishTask.getTaskName()+AbstractFactory.FINISHED);//任务结束，删除任务执行对应的任务完成总数
	//				AbstractFactory.percent.remove(publishTask.getTaskName()+AbstractFactory.FAIL);//任务结束，删除任务执行对应的任务失败总数
	//				AbstractFactory.percent.remove(publishTask.getTaskName()+AbstractFactory.TOTAL);//任务结束，删除任务执行对应的任务总数
				}
				generatable.savePublishTask(publishTask);
			}
		}
	}
	
	protected abstract File getTargetFile();
	
	protected abstract void initRootMap();
	
	protected abstract void logInfo(PublishTask publishTask,boolean success,Throwable t);
}